编程思想:解决问题之方法论
最近 AI 开源类项目大爆发,运行所需的硬件门槛也在不断降低,相信很多朋友都跃跃欲试。但是,作为编程小白,如何快速上手呢?本文将从一个新手小白的角度,分享一些经验。它作为一篇入门级文章,不限于某一技术,其思想是通用的,希望可以帮大家拨开技术的迷雾。问题不能被穷举,培养分析,定位,解决问题的能力才是我们唯一的出路!
案例分享
很多人可能都有类似的卡壳经历,希望我解决问题的思路可以给你带来一些启发!
我在技术群里常说的一句话就是,现在主流程序(可以应用于生产的项目)的报错机制已经很健全了,你关心的问题,全在报错信息上,但是很多初学者就是不关注这些。遇到问题,随手将报错截图丢入技术群就问:“各位大佬,我这问题怎么解决呀,在线急等”。最后这些信息基本都淹没在了群消息里,等不到回音。这种解决问题的方式在我看来是低效且错误的,即使问题得到解决,也不能帮助你获得任何技术上的提升(知其然不知其所以然)。分享一个案例,方便大家进行理解。
背景介绍
今天微信有个朋友(非编程人员)在使用 LabelImg[1] 项目时,因为把依赖环境搞乱了,导致 LabelImg 无法正常使用,给我丢了一个报错截图,寻求帮助。看到这个信息,大家可以想一下:如果是你,你会如何处理分析,并给出解决方案?
报错信息
(yolov7) E: \ZM\XXX\bridge engineering\machine learning\data scripts\original code\yolov7-main›labelImg
Fatal error in launcher: Unable to create process using '"D: \ProgramData\Anaconda3\envs\yolov7\python.exe" "E:\ProgramData\Anaconda3\envs\yolov7\Scripts\labelImg.exe"': ???????????
首先我对 labelImg 一无所知,但多年来积累的编程经验可以帮助我快速定位问题。现在我就把这个问题分析流程分享给大家。首先从截图我们可以获得以下关键信息:
启动或运行 labelImg 报错了
启动器在创建进程时需要用到 Python 和 Anaconda3,但是却产生了一个 xxxx 的报错信息
基于这两点分析我们就可以对提问者进行 QA 对话,进一步缩小错误范围。以下是稍加整理的部分对话内容:
第一轮对话
lencx
: 你是不是改过环境变量之类的朋友
: 对的,我之前都是安装在 d 盘的,后来全部迁移到 e 盘了,迁移后,也能打开正常使用,几天没用,再打开就这样了
第二轮对话
lencx
: 看报错你是启动 labelimg 它去 d 盘找 python 环境,结果没找到朋友
: 对的对的,然后我 d 盘又没有那个 python 环境了,所以我该怎么更改一下呢第三轮对话
lencx
: 你怎么安装的我不清楚,我是建议你将 python 的路径配置到系统变量中,这样是全局的,然后让 labelimg 去系统里找,你应该不是程序员吧(因为我从 TA 迁移目录,而未考虑路径变化会导致程序潜在问题,做出猜测确认身份,方便我后续针对 TA 的身份讲解),我觉得你现在环境都搞乱了朋友
: 我不是程序员,才接触没多久,论文需要用深度学习,那该怎么解决呢,是要全部卸载重装吗第四轮对话
lencx
: 是的,你可以搜一下相关配置,直接搜 anaconda,python 系统环境配置,应该能找到相关文章教程,你现在的问题是 anaconda,python,labelimg 三个环境依赖找的有点混乱,或者你将这个错误丢给 chatgpt(目前特定问题咨询 chatgpt 也是不错的选择),问它怎么解决朋友
: 我 chatGPT 暂时无法使用了,那我把现有的环境变量,关于 python 方面的都要删掉,然后再重装,配置,是这个意思吗?第五轮对话(本来事情到第四轮对话就该结束了,但是考虑到第四轮 TA 的回答有点毫无头绪的感觉,我猜测 TA 应该不是根据官方文档来进行环境安装的,于是我追加了第五轮询问)
lencx
: 那我问一下你的 anaconda,python 是根据什么安装的,直接看的官方文档还是别人写的教程朋友
: 别人写的教程第六轮对话(因为第五轮 TA 的回答让我确定了 TA 的安装环境步骤是根据别人教程来的,所以我追加此轮对话想进一步确认 TA 所看教程的质量到底如何)
lencx
: 额,我大概知道了,一般这种根据教程都很坑,环境变量的问题,很多教程都不会讲细节。你是下载这个安装器吗?朋友
: 不是的lencx
: 它应该会自动创建环境变量朋友
: 那我现在需要把现有的环境变量都给删掉吗lencx
: 好吧,你肯定是通过命令行在下载安装,然后需要配置朋友
: 好像是的
解决方案
事情到这里差不多整个都清楚了,接下来我给 TA 发了 Anaconda 安装[2],Anaconda 常见问题[3],Python 安装[4],LabelImg 安装[5] 官方文档,说了具体的安装步骤。然后跟 TA 说其实只看 LabelImg 安装文档就够了,它里面的步骤会指引你去寻找依赖。
朋友
: 我按照你发的这些文档重新安装一遍,之前我根据别人的教程,配置的更乱,后来重装系统了,又配置了一下,正常了,前一阵我迁移了盘,就又成现在这样了lencx
: 很多人教程都是瞎写,水平参差不齐。东一榔头西一棒,瞎介绍,没有逻辑朋友
: 根据有的教程弄完之后,一塌糊涂lencx
: 我要是写这个教程,首先就是 LabelImg 安装文档,然后它里面的第一步会让你去安装 anaconda,安装 anaconda 需要 python 3.10,所以环境三步就搞定了。程序是有相关性的,它的运行需要环境或者前置依赖,这个顺序很重要,不写清楚,人很容易懵逼。不然不知所以,就知道知道安装了一大坨,也不知道每一步是干啥朋友
: 真的就是这样的,我看有的教程,就是一脸懵,完全不知道要从哪下手lencx
: 以后尝试新技术,第一步就是看文档,很多技术的 readme 里都会写 install,如果 readme 里没有 install 这一步,都是垃圾项目(基本主流项目这是必备项)
案例小结
在这里,朋友和教程可能都犯了一些错误:
朋友
没有看文档的习惯
:抛开教程写作者水平不谈,自己在使用一门技术或工具时,一定要自己去了解它本身的一些东西(比如官方文档),很多教程面向的人群并非都是小白用户。底层知识欠缺,考虑不到问题的相关性
:自己在迁移文件路径时,未考虑可能带来的潜在风险。缺少解决问题的方法论
:一旦遇到问题或异常,毫无头绪,则自乱阵脚。...
教程(这里我并未看到原教程,故根据我在技术社区看到的各类文章来总结)
很多作者可能是用爱发电,记录自己的一些问题,简单回顾,所以不会考虑上下文。
抄袭搬运,作者自己也是一知半解,内容东拼西凑,逻辑混乱,误导读者。
技术工具类文章,常常会牵扯到大量术语或引用,一些作者会丢弃这些细节。作者需要考虑自己的文章受众,定位很重要,它将直接影响你的文章质量。
...
这里还有一个小细节,在第一轮对话中,朋友有这样一个描述:迁移后,也能打开正常使用,几天后再次打开就错误了。为什么呢?我在这里给出自己的一个猜测:迁移文件后,应用程序依然维持原有环境或内存信息(正常情况:在文件夹移动之后,这个错误就应该会出现了)。几天后,就意味着电脑可能经历过关机或者关闭应用的情况,这时应用会重新初始化加载,出现错误。
吐槽抱怨并不能让自己成长,原创类教程的出发点是分享,我们只能感恩(搬运抄袭除外)。正是因为他们的分享才让我们少走很多弯路,少踩很多坑。在教程内容不足的情况下,自己要具备扩展阅读的能力(比如文章中提到的术语,工具,名词等等,不清楚的,一知半解的都可以借助浏览器进行二次检索)。扩展阅读是高效学习的重要途径,它会让零散的知识最终形成一张很大的网。在我看来:无用知识并不存在,特定场景下,它就是那把可以开锁的钥匙
。
很多初学者经常会犯的一个错误就是:过度依赖第三方教程
。记住,除官方教程外就没有什么是权威的。而且它会制造大量的噪音,比如教程的版本和官方的差异化而导致的坑数不胜数,这里不再深入讨论。所以看教程的一个重要原则,它只是帮我打开思路,以窥全貌:轻度使用,越轻度越好。关键具体信息一定要去官网,不要怕麻烦
。
方法论
编程思想
编程思想是一种解决问题的方法论,它包括了分析问题、设计算法、编写代码、测试和优化等一系列环节。其核心是:将复杂的问题分解为简单的子问题,并通过编程语言来实现解决方案
。对于普通人来说,编程思想可以帮助我们更好地理解计算机科学,提高解决问题的能力,并可以应用在日常生活中。可以概括为以下几点:
抽象
:将问题简化,忽略不必要的细节,从而更容易地理解问题本质。(在日常生活中,可以通过抽象来简化复杂问题,将注意力集中在关键点上)分解
:将复杂问题分解成若干个简单的子问题。通过解决这些子问题,最终解决整个问题。(在日常生活中,面临的问题往往也很复杂,学会分解问题可以帮助我们更有效地解决问题)模式识别
:在解决问题时,尝试识别已知的模式和结构,从而找到更好的解决方案。(在日常生活中,可以通过模式识别来提高解决问题的效率)算法思维
:设计一系列步骤来解决问题。算法思维强调逻辑性和条理性,有助于我们在解决问题时思路清晰。迭代与反馈
:通过不断地测试、调整和优化,逐步改进解决方案。(在日常生活中,可以借鉴这种思维方式,不断地尝试和改进,提高解决问题的能力)
程序员如何思考?
遇到问题,先学会理解问题并正确提问,是得出正确结论的前提。尽可能多得收集信息,来帮助自己排除影响因素。找到问题原因,总结经验教训比甩锅更有意义。在这里我想分享一个来自 How does a programmer think? - Quora[6] 的回答:
Josh Osborne[7] - 程序员不会以一种特定的方式思考,但我认为好的程序员往往具有非程序员不常见的一些特质:
他们倾向于放弃一个好主意以寻求更好的主意,即使好主意是他们自己的,而更好的主意来自他们不喜欢的人。
他们更愿意相信自己犯了错误(你知道90%的调试是什么吗?追踪你自己的错误,很少情况下你会发现你用正确的参数调用了系统库,并从程序中得到了垃圾……通常是你提供了错误的参数或已经破坏了程序状态)。
他们需要一段时间来理解问题,然后再给出答案。
他们经常沉迷于提出正确的问题。
这两者都可以表现为对语言/词汇选择挑剔(看看我回答这个问题时做的第一件事情)。
在出现问题之后,他们想要找出原因,不是为了归咎于特定的人,而是为了确保不再犯同样的错误。
他们并不没有情感,但是在做决定时可以经常将情感置于一旁。有时是自然而然地这样做,有时是通过做出本能的选择,隔离推动它的情感,然后再做出选择。“是啊,要达到那种状态,你真的必须对程序撒谎好几次,那时谁真的在乎那个用户呢。叹气,好吧,或者他们连续三次读错了问题,或者猫走过键盘,好的,我们怎么从这个状态中恢复?”
在怀疑时,不要随意行动或做感觉最好的事情,而是要做收集最多信息的事情,或者是收集一些信息但影响最小的事情。
总结
简单来说,编程思维其实就是解决所有问题的方法论,它是一个通用思想。作为普通人,我们可以从以下几个方面来借鉴编程思想:
重要的事情说三遍:看文档!看文档!看文档!(所有的困惑,文档或搜索引擎都会给你答案)
将问题抽象简化,忽略不必要的细节,从而更容易地理解问题本质。
将复杂问题分解成若干个简单的子问题。通过解决这些子问题,最终解决整个问题。
培养逻辑思维和条理性,在解决问题时,学会按照一定的顺序和逻辑来进行思考。
当已有知识无法处理时,则需要借助搜索引擎,扩大检索范围,寻求解决问题的线索。
善于总结经验教训,并将问题进行泛化总结,使其可以迁移到其他领域。
抽象除了简化问题,也是提取关键词分解问题的核心,它会将特定问题转变为一般问题,然后分步求解。求解过程中,这些关键词可以作为搜索引擎的输入,对问题进一步检索。泛化总结是为了将特定问题的解转化为一般问题的解,也就是所谓的举一反三(它不是一个具体的结果或结论,而是解决问题的过程)。
References
LabelImg: https://github.com/heartexlabs/labelImg
[2]Anaconda 安装: https://docs.anaconda.com/free/anaconda/install/windows
[3]Anaconda 常见问题: https://docs.anaconda.com/free/anaconda/reference/troubleshooting
[4]Python 安装: https://www.python.org/downloads/windows
[5]LabelImg 安装: https://github.com/heartexlabs/labelImg#windows--anaconda
[6]How does a programmer think? - Quora: https://qr.ae/py1V3
[7]Josh Osborne: https://www.quora.com/profile/Josh-Osborne-6